package io.jsen.meta.diff.watch;

import io.jsen.meta.diff.obj.MetaObject;
import io.jsen.meta.diff.obj.complex.MetaCollection;
import io.jsen.meta.diff.obj.complex.MetaComplex;
import io.jsen.meta.diff.obj.complex.MetaMap;
import io.jsen.meta.diff.obj.special.MetaDelete;
import io.jsen.meta.diff.obj.special.MetaNull;
import io.jsen.meta.diff.support.MetaChangeModifier;
import io.jsen.meta.diff.support.MetaModifier;

import java.util.Collection;
import java.util.function.Consumer;

/**
 * @author jsen
 * @date 2021/05/01
 **/
public class MetaTreePrint {

    private static final String TAB = "     ";

    public static void print(MetaObject<?, ?> metaObject, Consumer<String> print) {
        String prefix = "";
        innerPrint(metaObject, print, prefix);
    }

    private static void innerPrint(MetaObject<?, ?> metaObject, Consumer<String> print, String prefix) {
        if (metaObject == null) {
            return;
        }
        if (metaObject instanceof MetaDelete || metaObject instanceof MetaNull) {
            return;
        }
        int modifier = metaObject.getModifier();
        if (!MetaModifier.anyComplex(modifier)) {
            print.accept(prefix + getFieldName(metaObject) + "=" + metaObject.getVal());
            return;
        }
        print.accept(prefix + getFieldName(metaObject));
        Collection<MetaObject<?, ?>> collection = null;
        if (MetaModifier.isMap(modifier)) {
            collection = ((MetaMap<?>) metaObject).getVal().values();
        } else if (MetaModifier.isCollection(modifier)) {
            collection = ((MetaCollection) metaObject).getVal();
        } else if (MetaModifier.isComplex(modifier)) {
            collection = ((MetaComplex) metaObject).getVal().values();
        }
        if (collection != null) {
            printCollection(collection, print, prefix + TAB);
        }
    }

    private static String getFieldName(MetaObject<?, ?> metaObject) {
        Object key = metaObject.getMetaRelation().getMetaField().getKey();
        String typeName = metaObject.getMetaRelation().getMetaField().getFieldDefine()
                .getCurrentFieldClass().getSimpleName();
        if (key == null) {
            return change(metaObject) + "[" + typeName + "]";
        }
        return change(metaObject) + key + "[" + typeName + "]";
    }

    private static String change(MetaObject<?, ?> metaObject) {
        return "(" + MetaChangeModifier.getDesc(metaObject.getModifier()) + ") ";
    }

    private static void printCollection(Collection<MetaObject<?, ?>> collection,
                                        Consumer<String> print, String prefix) {
        collection.forEach(obj -> innerPrint(obj, print, prefix));
    }
}
